package com.dlee.mvc.container;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.dlee.mvc.annotion.After;
import com.dlee.mvc.annotion.Aspect;
import com.dlee.mvc.annotion.Before;
import com.dlee.mvc.annotion.Controller;
import com.dlee.mvc.annotion.RequestMapping;
import com.dlee.mvc.annotion.Resource;
import com.dlee.mvc.annotion.Service;
import com.dlee.mvc.aop.CglibProxy;
import com.dlee.mvc.aop.JdkProxy;
import com.dlee.mvc.exception.RequestUrlRepeatException;
import com.dlee.mvc.model.AspectMapping;
import com.dlee.mvc.model.UrlMapping;
import com.dlee.mvc.parse.ClassAnnotationParse;
import com.dlee.mvc.parse.FieldAnnotationParse;
import com.dlee.mvc.util.FileUtil;
import com.dlee.mvc.util.StringUtils;

public final class BeanContainer
{
    private static Log logger = LogFactory.getLog (BeanContainer.class);
    //存储实例化bean
    private static final Map <String, Object> BEAN_PROPERTIES = new HashMap <String, Object> ();
    //存储url和controller映射
    private static final Map <String, UrlMapping> MAP_URL_MAPPING = new HashMap <String, UrlMapping> (30);
    //存储是增强的bean信息
    private static final List <AspectMapping> MAP_ASPECT_MAPPING = new ArrayList <AspectMapping> (30);
    private static final String CLASS_SUFFIX = "class";
    public static ContextEnvironment contextEnvironment;
    private static List <File> lstClassFile;

    public static void init (ContextEnvironment contextEnvironment)
    {
        BeanContainer.contextEnvironment = contextEnvironment;
        scanAnnotionClassFile ();
        initBean (contextEnvironment.getContextPath ());
    }

    /**
     * 获取有注解的类
     */
    public static void scanAnnotionClassFile ()
    {
        // 获取classpath,如：f:/a/b/c/class/
        String strClasspath = BeanContainer.class.getResource ("/").getPath ();
        String[] strPackages = BeanContainer.contextEnvironment.getAnnotationScanPath ().split ("\\.");
        for (String pack : strPackages)
        {
            strClasspath += File.separator + pack;
        }
        // 取路径下的所有类
        File objFile = new File (strClasspath);
        lstClassFile = FileUtil.getAllFile (objFile, CLASS_SUFFIX, BeanContainer.contextEnvironment.getAnnotationScanPath ());
    }

    /**
     * 实例化bean，对注入属性
     * @param contextPath
     */
    public static void initBean (String contextPath)
    {
    	//先解析出类
        for (File classFile : lstClassFile)
        {
            try
            {
            	new ClassAnnotationParse().parse(classFile, contextPath);
            }
            catch (ClassNotFoundException e)
            {
                logger.error ("class not found:", e);
            }
            catch (SecurityException e)
            {
                logger.error ("SecurityException:", e);
            }
        }
        //再给含有注解的类的属性进入注入
        for (File classFile : lstClassFile)
        {
            try
            {
            	new FieldAnnotationParse().parse(classFile, contextPath);
            }
            catch (ClassNotFoundException e)
            {
                logger.error ("class not found:", e);
            }
            catch (SecurityException e)
            {
                logger.error ("SecurityException:", e);
            }
        }
    }

    /**
     * 解析aop配置信息
     * 
     * @param targetClass
     * @param aspect
     */
    public static void initAspect (Class targetClass, Aspect aspect)
    {
        String classNameId = StringUtils.lowerCaseFirstChar (targetClass.getSimpleName ());
        AspectMapping am = new AspectMapping ();
        am.setBeanId (classNameId);
        am.setPath (aspect.packagePath ());
        am.setAopMethod (aspect.methodName ());
        Method[] methods = targetClass.getDeclaredMethods ();
        for (Method method : methods)
        {
            Before before = method.getAnnotation (Before.class);
            After after = method.getAnnotation (After.class);
            if (before != null)
            {
                am.setBeforeMethod (method.getName ());
            }
            else if (after != null)
            {
                am.setAfterMethod (method.getName ());
            }
        }
        MAP_ASPECT_MAPPING.add (am);
    }

    public static AspectMapping findAspectMapping (String className)
    {
        for (AspectMapping am : MAP_ASPECT_MAPPING)
        {
            int index = className.indexOf (am.getPath ());
            if (-1 != index)
            {
                return am;
            }
        }
        return null;
    }

    /**
     * 初始化类
     * 
     * @param targetClass
     */
    public static void newInstanceClass (Class targetClass)
    {
        try
        {
            String classNameId = StringUtils.lowerCaseFirstChar (targetClass.getSimpleName ());
            Object classNewInstance = null;
            // 从Map中取该类的实例，如果该class已经实例化了，则不用再实例化
            if (null != getBean (classNameId))
            {
                classNewInstance = getBean (classNameId);
            }
            else
            {
                // 如果该类的实例不存在，则实例化后存储到Map中
                classNewInstance = targetClass.newInstance ();
                // 将对象放入到map中
                BEAN_PROPERTIES.put (classNameId, classNewInstance);
            }
        }
        catch (InstantiationException e)
        {
            e.printStackTrace ();
        }
        catch (IllegalAccessException e)
        {
            e.printStackTrace ();
        }
    }

    /**
     * 初始化类的属性
     * 
     * @param targetClass
     */
    public static void injectProperties (Class targetClass)
    {
        try
        {
            String classNameId = StringUtils.lowerCaseFirstChar (targetClass.getSimpleName ());
            Object classParentInstance = getBean (classNameId);

            if (null == classParentInstance)
            {
                throw new InstantiationException (targetClass.getName () + "没有初始化");
            }

            // 取类中标有@Resource的属性，然后实例化该类
            // Field[] fields = classNewInstance.getClass ().getDeclaredFields
            // ();
            Field[] fields = targetClass.getDeclaredFields ();

            for (Field field : fields)
            {
                Resource resource = field.getAnnotation (Resource.class);
                if (resource != null)
                {
                    // 关键，设置私有或受保护的字段可以访问
                    field.setAccessible (true);
                    String fieldClassNameId = StringUtils.lowerCaseFirstChar (field.getType ().getSimpleName ());
                    Class objFieldObject = Class.forName (field.getType ().getName ());
                    Object classFieldInstance = null;
                    // 如果属性是接口
                    if (objFieldObject.isInterface ())
                    {
                        // 找出接口类的实现类
                        Class subClass = subClass (objFieldObject, BeanContainer.contextEnvironment.getAnnotationScanPath ());
                        if (null == subClass)
                        {
                            throw new InstantiationException (field.getType ().getName () + "初始化失败，没找到实现类");
                        }
                        fieldClassNameId = StringUtils.lowerCaseFirstChar (subClass.getSimpleName ());
                        // 动态代理
                        classFieldInstance = getBean (fieldClassNameId);
                        // 目标类为接口，使用jdk动态代理
                        if (null != classFieldInstance)
                        {
                            // 取aop配置的信息
                            AspectMapping am = findAspectMapping (objFieldObject.getName ());
                            if (null != am)
                            {
                                JdkProxy jdkProxy = new JdkProxy (classFieldInstance, am);
                                // classFieldInstance = Proxy.newProxyInstance
                                // (BeanContainer.class.getClassLoader (), new
                                // Class<?>[]{objFieldObject}, jdkProxy);
                                classFieldInstance = jdkProxy.createProxy (objFieldObject);
                            }
                        }
                        else
                        {
                            // 抛出异常
                        }

                    }
                    else
                    {
                        classFieldInstance = getBean (fieldClassNameId);
                        if (null != classFieldInstance)
                        {
                            // cglib处理增强
                            AspectMapping am = findAspectMapping (objFieldObject.getName ());
                            if (null != am)
                            {
                                CglibProxy cp = new CglibProxy ();
                                classFieldInstance = cp.createProxy (classFieldInstance, am);
                            }
                        }
                        else
                        {
                            // 抛出异常
                        }
                    }
                    // 取得实例,注入到属性中
                    field.set (classParentInstance, classFieldInstance);
                }
            }
        }
        catch (InstantiationException e)
        {
            e.printStackTrace ();
        }
        catch (IllegalAccessException e)
        {
            e.printStackTrace ();
        }
        catch (ClassNotFoundException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace ();
        }
    }

    /**
     * 解析url映射
     * 
     * @param targetClass
     * @param contextPath
     * @param url
     * @param classPath
     */
    public static void resolveMapping (Class targetClass, String contextPath, String url, String classPath)
    {
        // 存储映射的类方法和参数
        UrlMapping objUrlMapping;
        // 获取声明的方法
        Method[] objMethod = targetClass.getDeclaredMethods ();
        // 存在方法
        if (null != objMethod && objMethod.length != 0)
        {
            for (int i = 0; i < objMethod.length; i++)
            {
                Annotation objMethodAnnotation = objMethod[i].getAnnotation (RequestMapping.class);

                // 取方法上的注解
                // RequestMapping objRequestMapping =
                // objMethod[i].getClass().getAnnotation(RequestMapping.class);
                if (null != objMethodAnnotation && objMethodAnnotation.annotationType ().equals (RequestMapping.class))
                {
                    //封装请求信息
                    RequestMapping objRequestMapping = (RequestMapping) objMethodAnnotation;
                    objUrlMapping = new UrlMapping ();
                    objUrlMapping.setClassPath (classPath);
                    objUrlMapping.setMethodName (objMethod[i].getName ());
                    objUrlMapping.setParameterArray (objMethod[i].getParameterTypes ());
                    // 将路径转成匹配
                    String strPath = contextPath + url + objRequestMapping.value ();
                    if (null == MAP_URL_MAPPING.get (strPath))
                    {
                        MAP_URL_MAPPING.put (strPath, objUrlMapping);
                    }
                    else
                    {
                        throw new RequestUrlRepeatException ("url重复");
                    }
                }
            }
        }

    }

    public static Class subClass (Class parentClass, String scanPath)
    {
        for (File classFile : lstClassFile)
        {
            String classFullPath = FileUtil.getClassFullName (classFile.getPath (), scanPath);
            try
            {
                Class objClass = Class.forName (classFullPath);
                //判断是否是父子关系
                if (parentClass.isAssignableFrom (objClass))
                {
                    return objClass;
                }
            }
            catch (ClassNotFoundException e)
            {
                e.printStackTrace ();
            }
        }
        return null;
    }

    /**
     * 取类的实例
     * 
     * @return 对象
     */
    public static Object getBean (String id)
    {
        return BEAN_PROPERTIES.get (id);
    }

    public static UrlMapping getMapUrlMapping (String url)
    {
        return MAP_URL_MAPPING.get (url);
    }

    public static void main (String[] args)
    {
        String strClasspath = BeanContainer.class.getClassLoader ().getResource ("").getPath ();
        System.out.println (strClasspath);
        String str = Thread.currentThread().getContextClassLoader().getResource("").getPath();
        System.out.println (str);
    }
}
